/* Copyright (c) 2008, 2009, 2010, 2011 Damian Kmiecik
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
     distribution.
   * Neither the name of the copyright holders nor the names of
     contributors may be used to endorse or promote products derived
     from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGE. */

#ifndef _ENC28J60_H
#define	_ENC28J60_H

#ifdef	__cplusplus
extern "C"
{
#endif

#include "hardware.h"
#include "main.h"
#include "enc28j60reg.h"

#define ENC_DEBUG	DEBUG

// Max frame length which the conroller will accept:
#define ENC28J60_MAX_LEN	1514
// Transmit buffer start
#define ENC28J60_TXST		(0x1FFF-ENC28J60_MAX_LEN-1)
// Transmit buffer end
#define ENC28J60_TXND		0x1FFF
// Receive buffer start
#define ENC28J60_RXST		0x0000
// Receive buffer end
#define ENC28J60_RXND		(ENC28J60_TXST-1)

/**
 * Read Control Register Command
 * @param uint8_t address
 * @return uint8_t
 */
extern uint8_t enc28j60ReadCR(const uint8_t address);

/**
 * Write Control Register Command
 * @param uint8_t address
 * @param uint8_t data
 */
extern void enc28j60WriteCR(const uint8_t address, const uint8_t data);

/**
 * Read PHY Register Command
 * @param uint8_t address
 * @return uint16_t
 */
extern uint16_t enc28j60ReadPHY(const uint8_t address);

/**
 * Write PHY Register Command
 * @param uint8_t address
 * @param uint8_t data
 */
extern void enc28j60WritePHY(const uint8_t address, const uint16_t data);

/**
 * Set bits in register
 * @param uint8_t address
 * @param uint8_t mask
 */
extern void enc28j60SetBF(const uint8_t address, const uint8_t mask);

/**
 * Clear bits in register
 * @param uint8_t address
 * @param uint8_t mask
 */
extern void enc28j60ClearBF(const uint8_t address, const uint8_t mask);

/**
 * Bank Select
 * Check if destination address is in current bank
 * @param uint8_t address
 */
extern void enc28j60BankSel(const uint8_t address);

/**
 * ENC28J60 initialize
 * Must be run before any usage of ENC28J60 functions
 * @param uint8_t* macAddr
 */
extern void enc28j60Init(void);

/**
 * Read Buffer Memmory Command
 * @param uint16_t len
 * @param uint8_t* data
 */
extern void enc28j60ReadBM(uint16_t len, uint8_t* data);

/**
 * Write Buffer Memmory Command
 * @param uint16_t len
 * @param uint8_t* data
 */
extern void enc28j60WriteBM(uint16_t len, const uint8_t* data);

/**
 * Send Packet
 * @param uint16_t len
 * @param uint8_t* packet
 */
extern void enc28j60SendPacket(uint16_t len, const uint8_t* packet);

/**
 * Receive Packet
 * @param uint16_t maxlen
 * @param uint8_t* packet
 * @return uint16_t
 */
extern uint16_t enc28j60ReceivePacket(const uint16_t maxlen, uint8_t* packet);

/**
 * Set Clock source speed
 * @param uint8_t clk
 */
inline void enc28j60SetCLK(const uint8_t clk)
{
	enc28j60WriteCR(ENC28J60_REG_ECOCON, clk);
}

/**
 * Read link status
 */
extern uint8_t enc28j60LinkStatus(void);

#ifdef	__cplusplus
}
#endif

#endif	/* _ENC28J60_H */
